﻿using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;

namespace Common.Infrastructure
{
    public static class QueryableOrderExtensions
    {
        /// <summary>
        /// 设置排序.
        /// </summary>
        /// <typeparam name="T">类型.</typeparam>
        /// <param name="query">列表.</param>
        /// <param name="type">排序级别 0-by 1-thenby.</param>
        /// <param name="sort">排序字段.</param>
        /// <param name="order">排序方式 0-升序 1-降序.</param>
        /// <returns>排序后列表.</returns>
        public static IQueryable<T> SetQueryableOrder<T>(this IQueryable<T> query, int type, string sort, int order)
        {
            LibCheckNullUtils.CheckNull(sort, "Sort");
            ParameterExpression parameterExpression = Expression.Parameter(typeof(T), "t");
            Expression expression = parameterExpression;
            if (Nullable.GetUnderlyingType(expression.Type) != null)
            {
                expression = Expression.Property(expression, "Value");
            }

            expression = QueryableOrderExtensions.GetPropertyLambdaExpression(expression, sort);
            LambdaExpression expression2 = Expression.Lambda(expression, new ParameterExpression[] { parameterExpression });
            string methodName = type == 0 ? ((order == 1) ? "OrderByDescending" : "OrderBy") : ((order == 1) ? "ThenByDescending" : "ThenBy");
            query = query.Provider.CreateQuery<T>(Expression.Call(
                typeof(Queryable),
                methodName,
                new Type[] { typeof(T), expression.Type },
                new Expression[] { query.Expression, Expression.Quote(expression2) }));
            return query;
        }

        private static Expression GetPropertyLambdaExpression(Expression body, string fileName)
        {
            string[] array = fileName.Split(new char[]
            {
                '.',
            });
            Type type = body.Type;
            string[] array2 = array;
            for (int i = 0; i < array2.Length; i++)
            {
                string name = array2[i];
                PropertyInfo property = type.GetProperty(name);
                Contract.Assume(property != null);
                type = property.PropertyType;
                body = Expression.MakeMemberAccess(body, property);
            }

            return body;
        }
    }
}
